import Util from './util';

const Timeout = 6000;

function toDataJSON(data){
  let text = Util.arrayBufferToString({data});
  return JSON.parse(text);
}

function toStringMesssage(message){
  return message instanceof String ? message : JSON.stringify(message);
}

function createServer(e){
  const { config, onReceive, onError, onConnect, onDisconnect } = e;
  let connectInfo;
  let timer;
  const keepConnectInfo = function(){
    timer = setTimeout(function(){
      if(connectInfo){
        let otime = Date.now()-connectInfo.utime;
        if(otime<Timeout){
          keepConnectInfo();
          onReceive({ 
            localInfo:{}, 
            remoteInfo:connectInfo, 
            message:{ 
              otime,
              intent:'keep_connect'
            }
          });
          return;
        }
      }
      connectInfo=null;
      onDisconnect({ errMsg:'wait update is timeout'});
    },Timeout);
  };
  const closeTimer = function(){
    if(!timer) return;
    clearTimeout(timer);
    timer=undefined;
  };

  let udp = wx.createUDPSocket();
  udp.onError(function(err){
    if(onError instanceof Function) onError(err);
    else console.error(err);
  });
  udp.onClose(function(){
    closeTimer();
  });
  udp.onMessage(function(res){
    const { localInfo, remoteInfo } = res;
    let message = Util.arrayBufferToString({data:res.message});
    message = Util.parseJSON(message);
    console.log('server receive data', message);
    let response;
    switch(message?.intent){
      case 'create_connect':
        {
          wx.showToast({
            title: 'create_connect',
          })
          let data = message.data;
          connectInfo = {
            address:remoteInfo.address,
            port:data.port || remoteInfo.port,
          };
          onConnect({
            remoteInfo:connectInfo,
            localInfo,
            message:data
          });
          response = {
            intent:message.intent,
            time:Date.now(),
            data:config,
          };
          //防抖处理
          closeTimer();
          keepConnectInfo();
          break;
        }
      case 'keep_connect':
        {
          wx.showToast({
            title: 'keep_connect',
          })
          if(connectInfo) {
            connectInfo.utime = Date.now();
            response = {
              intent:message.intent,
              time:Date.now(),
              data: 'ok'
            };
          }else{
            response = {
              intent:'create_connect',
              time:Date.now(),
              data:config,
            };
          }
          if(message.ntime) response.utime = response.time - message.ntime;
          break;
        }
      default:
        wx.showToast({
          title: 'default',
        })
        response = onReceive({ localInfo, remoteInfo, message });
    }
    if(!response) return;
    udp.send({
      address:remoteInfo.address,
      port:remoteInfo.port,
      message:toStringMesssage(response)
    });
  });
  let port = udp.bind(config.port);
  //let port = udp.bind();
  return {
    getPort(){
      return port;
    },
    close(){
      udp.close();
    }
  };
}

function sendMessage(e){
  if(e.autoClose==undefined) e.autoClose=true;
  const { message, port, remoteInfo, fail, success, autoClose } = e;
  let udp = wx.createUDPSocket();
  udp.onError(err=>{
    if(autoClose) udp.close();
    if(fail instanceof Function) fail(err);
    else console.error(err);
  });
  udp.onMessage(res=>{
    if(autoClose) udp.close();
    if(!(success instanceof Function)) return;
    const { remoteInfo, localInfo } = res;
    let message = Util.arrayBufferToString({data:res.message});
    message = Util.parseJSON(message);
    success(message,remoteInfo,localInfo);
  });
  udp.bind(port);
  udp.send({
    address:remoteInfo.address,
    port:remoteInfo.port,
    message:toStringMesssage(message)
  });
  return udp;
}

function connectServer(remoteInfo,e){
  const { config, onReceive, onError, onConnect, onDisconnect } = e;
  let connectInfo;
  console.log('connectServer', remoteInfo);
  wx.showToast({
    title: 'connectServer',
  })
  let timer,timer2;
  const closeTimer = function(){
    if(timer) {
      clearTimeout(timer);
      timer=undefined;
    }
    if(timer2) {
      clearTimeout(timer2);
      timer2=undefined;
    }
  };
  const clientUdp = wx.createUDPSocket();
  clientUdp.onClose(function(){
    closeTimer();
  });
  clientUdp.onError(function(err){
    closeTimer();
    if(onError instanceof Function) onError(err);
    else console.error(err);
  });
  clientUdp.bind();
  let time;
  let sendSign = function(){
    timer = setTimeout(function(){
      let message = {
        intent:'keep_connect',
        ntime:Date.now(),
      };
      if(!connectInfo){
        message.intent='create_connect';
        message.data=config;
      }
      clientUdp.send({
        address:remoteInfo.address,
        port:remoteInfo.port,
        message:JSON.stringify(message)
      });
      timer2 = setTimeout(function(){    
        connectInfo = null;
        onDisconnect({ errMsg:'the request timeout' });
      },Timeout);
    },config.time || 3000);
  };
  clientUdp.onMessage(function(res){
    //防抖处理
    closeTimer();
    const { localInfo,remoteInfo } = res;
    let message = Util.arrayBufferToString({data:res.message});
    message = Util.parseJSON(message);
    if(message.intent=='create_connect'){
      connectInfo = remoteInfo;
      onConnect({message:message.data,localInfo,remoteInfo});
    }else{
      if(time && message.otime==undefined) message.otime = Date.now() - time;
      onReceive({message,localInfo,remoteInfo});
      time = Date.now(); 
    }
    sendSign();
  });
  sendSign();
  return clientUdp;
}

function sendBroadcast(e){
  const { port, fail, success, showLoading } = e;
  let udp = wx.createUDPSocket();
  let timer;
  let list = [];
  function complete(callback){
    if(timer) {
      clearTimeout(timer);
      timer=null;
    }
    if(showLoading) wx.hideLoading();
    udp.close();
    callback();
  }
  if(fail instanceof Function){
    udp.onError(function(err){
      complete(function(){
        fail(err);
      });
    });
  }
  udp.onMessage(function(res){
    wx.showToast({
      title: 'BroadcastonMsg',
    })
    res.message = toDataJSON(res.message);
    list.push(res);
  });
  udp.bind();
  udp.send({
    address:'255.255.255.255',
    port: port,
    message: JSON.stringify({ intent: 'scan' })
  });
  timer = setTimeout(function(){
    complete(function(){
      if(success instanceof Function) success({ list });
    })
  }, e.timeout || 3000);
  if(showLoading) {
    wx.showLoading({
      title: showLoading instanceof String ? showLoading : '扫描中',
      mask: true
    })
  }
}

export default {
  toDataJSON,
  createServer,
  connectServer,
  sendBroadcast,
  sendMessage,
}